#include <ctype.h>
#include <stdarg.h>
#include <stdint.h>
#include "port/datatype.h"
#include "onps_errors.h"
#include "port/sys_config.h"
#include "port/os_datatype.h"
#include "one_shot_timer.h"
#include "sys_timer.h"
#include "protocols.h"

#if SUPPORT_PPP
#include "scp.h"
#include "ppp/negotiation_storage.h"
#include "ppp/ppp.h"
#endif

#define SYMBOL_GLOBALS
#include "port/os_adapter.h"
#undef SYMBOL_GLOBALS

#if SUPPORT_PPP
//* 在此指定连接modem的串行口，以此作为tty终端进行ppp通讯
const CHAR *or_pszaTTY[PPP_NETLINK_NUM] = { "SCP3" };
const ST_DIAL_AUTH_INFO or_staDialAuth[PPP_NETLINK_NUM] = {
    { "4gnet", "card", "any_char" },  /* 注意ppp账户和密码尽量控制在20个字节以内，太长需要需要修改chap.c中send_response()函数的szData数组容量及 */
                                      /* pap.c中pap_send_auth_request()函数的ubaPacket数组的容量，确保其能够封装一个完整的响应报文              */
};
ST_PPPNEGORESULT o_staNegoResult[PPP_NETLINK_NUM] = {
    {
        { 0, PPP_MRU, ACCM_INIT,{ PPP_CHAP, 0x05 /* 对于CHAP协议来说，0-4未使用，0x05代表采用MD5算法 */ }, TRUE, TRUE, FALSE, FALSE },
        { IP_ADDR_INIT, DNS_ADDR_INIT, DNS_ADDR_INIT, IP_ADDR_INIT, MASK_INIT }, 0
    },

    /* 系统存在几路ppp链路，就在这里添加几路的协商初始值，如果不确定，可以直接将上面预定义的初始值直接复制过来即可 */
};
#endif

//* 协议栈内部工作线程列表
//* ==================================================================================================
#define THOSTIMERCOUNT_STK_SIZE	  256 * 4
#define THOSTIMERCOUNT_TIMESLICE  10

#if SUPPORT_PPP
#define THPPPHANDLER_STK_SIZE	  384 * 4
#define THPPPHANDLER_TIMESLICE  10
#endif

const static STCB_PSTACKTHREAD lr_stcbaPStackThread[] = {
	{ thread_one_shot_timer_count, (void *)0, "OSTimerCnt", THOSTIMERCOUNT_STK_SIZE, THOSTIMERCOUNT_PRIO, THOSTIMERCOUNT_TIMESLICE }, 
#if SUPPORT_PPP
	{ thread_ppp_handler, (void *)0, "THPPPHandler", THPPPHANDLER_STK_SIZE, THPPPHANDLER_PRIO, THPPPHANDLER_TIMESLICE }, 
#endif	
}; 
//* ==================================================================================================


//* 当前线程休眠指定的秒数，参数unSecs指定要休眠的秒数
void os_sleep_secs(UINT unSecs)
{
	rt_thread_mdelay(unSecs * 1000); 
}

//* 当前线程休眠指定的毫秒数，单位：毫秒 
void os_sleep_ms(UINT unMSecs)
{
    rt_thread_mdelay(unMSecs); 
}

//* 获取系统启动以来已运行的秒数（从0开始）
UINT os_get_system_secs(void)
{
	return GetElapsedSecs(); 
}

void os_thread_onpstack_start(void *pvParam)
{
	pvParam = pvParam; //* 避免编译器警告

	//* 建立工作线程
  rt_thread_t tid; 
	INT i; 
	for (i = 0; i < sizeof(lr_stcbaPStackThread) / sizeof(STCB_PSTACKTHREAD); i++)
	{
		tid = rt_thread_create(lr_stcbaPStackThread[i].pszThreadName, lr_stcbaPStackThread[i].pfunThread, RT_NULL, lr_stcbaPStackThread[i].unStackSize, lr_stcbaPStackThread[i].ubPrio, lr_stcbaPStackThread[i].unTimeSlice);  
    if(tid != RT_NULL)
      rt_thread_startup(tid); 
	}
}

HMUTEX os_thread_mutex_init(void)
{
	HMUTEX hMutex = rt_mutex_create("rt-mutex", RT_IPC_FLAG_FIFO);
  if(RT_NULL != hMutex)      
    return hMutex; 
    
	return INVALID_HMUTEX; //* 初始失败要返回一个无效句柄
}

void os_thread_mutex_lock(HMUTEX hMutex)
{
	rt_mutex_take(hMutex, RT_WAITING_FOREVER); 
}

void os_thread_mutex_unlock(HMUTEX hMutex)
{
	rt_mutex_release(hMutex);
}

void os_thread_mutex_uninit(HMUTEX hMutex)
{
	rt_mutex_delete(hMutex); 
}

HSEM os_thread_sem_init(UINT unInitVal, UINT unCount)
{
  unCount = unCount; //* 避免编译器警告
  
	HSEM hSem = rt_sem_create("rt-dsem", unInitVal, RT_IPC_FLAG_FIFO); 
  if(RT_NULL != hSem)
    return hSem; 

	return INVALID_HSEM; //* 初始失败要返回一个无效句柄
}

void os_thread_sem_post(HSEM hSem)
{
	rt_sem_release(hSem); 
}

INT os_thread_sem_pend(HSEM hSem, INT nWaitSecs)
{    
  if(nWaitSecs)
    nWaitSecs = nWaitSecs * RT_TICK_PER_SECOND; 
  else
    nWaitSecs = RT_WAITING_FOREVER; 
  
	rt_err_t lRtnVal = rt_sem_take(hSem, nWaitSecs);
  if(RT_EOK == lRtnVal)
    return 0; 
  else if(-RT_ETIMEOUT == lRtnVal)
    return 1; 
  else    
    return -1; 
}

void os_thread_sem_uninit(HSEM hSem)
{
	rt_sem_delete(hSem);
}

#if SUPPORT_PPP
HTTY os_open_tty(const CHAR *pszTTYName)
{
	pszTTYName = pszTTYName; //* 避免编译器警告
	
	SCP3Init(115200, DATABIT_8, STOPBITS_1, PARITYTP_NO, FLOWCTLTP_NO);	 
	return 0; 
}

void os_close_tty(HTTY hTTY)
{
	hTTY = hTTY; //* 避免编译器警告
}

INT os_tty_send(HTTY hTTY, UCHAR *pubData, INT nDataLen)
{
	hTTY = hTTY; //* 避免编译器警告
	return (INT)SCP3Send(pubData, (uint32_t)nDataLen);
}

INT os_tty_recv(HTTY hTTY, UCHAR *pubRcvBuf, INT nRcvBufLen, INT nWaitSecs)
{
	hTTY = hTTY; //* 避免编译器警告
	return SCP3Recv(pubRcvBuf, (uint32_t)nRcvBufLen, nWaitSecs); 
}

void os_modem_reset(HTTY hTTY)
{
#if SUPPORT_PRINTF
  printf("start reset modem...\r\n");
#endif 	
  SCP3ReInit(); 
  
	M4G_POWER_OFF();
  os_sleep_secs(3); 	
	M4G_POWER_ON();
  os_sleep_secs(6); 
	
#if SUPPORT_PRINTF
  printf("reset modem succeeded.\r\n");
#endif 
}
#endif
